package com.zhou.JavaAndroidFirm.http;

import android.content.Context;

import com.zhou.JavaAndroidFirm.base.BaseApplication;
import com.zhou.JavaAndroidFirm.utils.LogUtils;
import com.zhou.JavaAndroidFirm.utils.NetWorkUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.X509TrustManager;

import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;

/**
 * @author Administrator
 * @date 2018/7/16 0016
 * @des
 */
public class HttpUtils {

    /*************************缓存设置*********************/
    /*
    1. noCache 不使用缓存，全部走网络

    2. noStore 不使用缓存，也不存储缓存

    3. onlyIfCached 只使用缓存

    4. maxAge 设置最大失效时间，失效则不使用 需要服务器配合

    5. maxStale 设置最大失效时间，失效则不使用 需要服务器配合 感觉这两个类似 还没怎么弄清楚，清楚的同学欢迎留言

    6. minFresh 设置有效时间，依旧如上

    7. FORCE_NETWORK 只走网络

    8. FORCE_CACHE 只走缓存
    */

    private Retrofit retrofit;
    private HttpService service;
    private OkHttpClient okHttpClient;
    private Context context;
    private static NetWorkConfiguration configuration;

    /**
     * 针对无网络情况下是否加载本地缓存数据
     * 默认为真
     *
     * @param loadDiskCache
     */
    public void setLoadDiskCache(boolean loadDiskCache) {
        isLoadDiskCache = loadDiskCache;
    }

    /**
     * 是否默认加载本地缓存数据
     * 默认为true
     */
    private boolean isLoadDiskCache = true;


    /**
     * 针对有网络情况下是否优先加载内存数据
     */
    public void setLoadMemoryCache(boolean loadMemoryCache) {
        isLoadMemoryCache = loadMemoryCache;
    }

    /**
     * 针对有网络情况下是否优先加载内存数据
     * 默认为否
     */
    private boolean isLoadMemoryCache = false;

    public HttpUtils(Context context) {
        this.context = context;
        if (configuration == null) {
            configuration = new NetWorkConfiguration(context);
        }
//        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
//        if (BuildConfig.LOG_DEBUG) {
//            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//        } else {
//            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
//        }
        Interceptor headInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request().newBuilder().addHeader("Content-Type", "application/json").build();
                return chain.proceed(request);
            }
        };
        if (configuration.getIsCache()) {
            okHttpClient = new OkHttpClient.Builder()
                    .readTimeout(configuration.getConnectTimeOut(), TimeUnit.SECONDS)
                    .connectTimeout(configuration.getConnectTimeOut(), TimeUnit.SECONDS)
                    .addInterceptor(mRewriteCacheControlInterceptor)
                    .addNetworkInterceptor(mRewriteCacheControlInterceptor)
                    .addInterceptor(new LogInterceptor())
                    .addInterceptor(headInterceptor)
                    .cache(configuration.getDiskCache())
                    .connectionPool(configuration.getConnectionPool())
                    .retryOnConnectionFailure(true)
                    .build();
        } else {
            okHttpClient = new OkHttpClient.Builder()
                    .readTimeout(configuration.getConnectTimeOut(), TimeUnit.SECONDS)
                    .connectTimeout(configuration.getConnectTimeOut(), TimeUnit.SECONDS)
                    .addInterceptor(new LogInterceptor())
                    .addInterceptor(headInterceptor)
                    .connectionPool(configuration.getConnectionPool())
                    .retryOnConnectionFailure(true)
                    .build();
        }

        if (configuration.getCertificates() != null) {
            okHttpClient = getOkHttpClient().newBuilder()
                    .sslSocketFactory(SSLUtil.getSslSocketFactory(configuration.getCertificates(), null, null))
                    .build();
        } else {
            okHttpClient = getOkHttpClient().newBuilder()
                    .sslSocketFactory(SSLUtil.getDefaultSslSocketFactory(), (X509TrustManager) SSLUtil.getTrustManager()[0])
                    .hostnameVerifier(SSLUtil.getHostnameVerifier())
                    .build();
        }

    }

    public RetrofitClient getRetofitClinet() {
        return new RetrofitClient(okHttpClient, configuration.getBaseUrl());
    }

    /**
     * 设置网络配置参数
     *
     * @param configuration
     */
    public static void setConFiguration(NetWorkConfiguration configuration) {
        if (configuration == null) {
            throw new IllegalArgumentException("ImageLoader configuration can not be initialized with null");
        } else {
            if (HttpUtils.configuration == null) {
                LogUtils.d("Initialize NetWorkConfiguration with configuration");
                HttpUtils.configuration = configuration;
            } else {
                LogUtils.d("Try to initialize NetWorkConfiguration which had already been initialized before. To re-init NetWorkConfiguration with new configuration ");
            }
        }
        if (configuration != null) {
            LogUtils.d("ConFiguration" + configuration.toString());
        }
    }

    /**
     * 获得OkHttpClient实例
     *
     * @return
     */
    public OkHttpClient getOkHttpClient() {
        return okHttpClient;
    }

    /**
     * 设置Coolie
     *
     * @return
     */
    public HttpUtils addCookie() {
        okHttpClient = getOkHttpClient().newBuilder()
                .cookieJar(new SimpleCookieJar())
                .build();
        return this;
    }

    /**
     * 设置HTTPS客户端带证书访问
     *
     * @param certificates 本地证书
     */
    public HttpUtils setCertificates(InputStream... certificates) {
        okHttpClient = getOkHttpClient().newBuilder()
                .sslSocketFactory(SSLUtil.getSslSocketFactory(certificates, null, null))
                .build();
        return this;
    }

    public static HttpUtils getInstance() {
        if (instance == null) {
            synchronized (HttpUtils.class) {
                if (instance == null) {
                    instance = new HttpUtils(BaseApplication.getAppContext());
                }
            }
        }
        return instance;
    }

    private static HttpUtils instance;


    private final Interceptor mRewriteCacheControlInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            //无网络情况下是否加载本地数据
            if (!NetWorkUtils.isNetConnected(BaseApplication.getAppContext()) && isLoadDiskCache) {
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
            }
            //有网络情况下是否优先加载内存数据
            else if (isLoadMemoryCache) {
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
            } else {
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_NETWORK)
                        .build();
            }

            Response response = chain.proceed(request);
            //有网络情况下，将网络请求得数据
            if (NetWorkUtils.isNetConnected(BaseApplication.getAppContext()) && configuration.getIsMemoryCache()) {
                //进行内存缓存
                return response.newBuilder()
                        .header("Cache-Control", "public, max-age=" + configuration.getmemoryCacheTime())
                        .removeHeader("Pragma")
                        .build();
            } else {
                //进行本地缓存数据
                if (configuration.getIsDiskCache()) {
                    return response.newBuilder()
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + configuration.getDiskCacheTime())
                            .removeHeader("Pragma")
                            .build();
                }
            }
            return response;
        }
    };
}
